#ifndef PART_TM4C123GH6PM
#define PART_TM4C123GH6PM
#endif
#include "stdint.h"
#include "stdbool.h"
#include "usart.h"
#include "inc/hw_memmap.h"
#include "inc/tm4c123gh6pm.h"
#include "inc/hw_ints.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include "string.h"

#include "key.h"
#include "lcd.h"
#include "num_str.h"

static void UART_init();
static void test();
static void UARTSend(const uint8_t *pucBuffer, uint32_t ulCount);
static void UARTtx(uint8_t data);

ModUart modUart = {
    .i              = 0,
    .memPool[0]     = '\0',
    .bytes          = 0,
    .needRefresh    = false,
    .isRunning      = false,
    .tx_data        = '\0',
    .uartInit       = UART_init,
    .test           = test,
    .send           = UARTSend,
    .tx             = UARTtx,
};

void UARTIntHandler(void) {
    uint32_t ui32Status;
    uint8_t c;
    ui32Status = UARTIntStatus(UART5_BASE, true);

    UARTIntClear(UART5_BASE, ui32Status);
    modUart.bytes = strlen(modUart.memPool);
    modUart.memPool[0] = '\0';
    modUart.i = 0;
    while(UARTCharsAvail(UART5_BASE)) {
        c = UARTCharGet(UART5_BASE);
        modUart.memPool[modUart.i++] = c;
    }
    if (strlen(modUart.memPool) < modUart.bytes)
        modUart.needRefresh = true;
}

void UART_init(void) {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART5);

    GPIOPinConfigure(GPIO_PE4_U5RX);
    GPIOPinConfigure(GPIO_PE5_U5TX);
    //
    // Enable processor interrupts.
    //
    IntMasterEnable();

    //
    // Set GPIO A0 and A1 as UART pins.
    //
    GPIOPinTypeUART(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    UARTConfigSetExpClk(UART5_BASE, SysCtlClockGet(), 115200, (UART_CONFIG_WLEN_8 |
                                                               UART_CONFIG_STOP_ONE |
                                                               UART_CONFIG_PAR_NONE));

    IntEnable(INT_UART5);
    UARTIntEnable(UART5_BASE, UART_INT_RX | UART_INT_RT);
}

void test() {
    uint8_t key = EMPTY_INPUT;
    uint32_t position;
    TFT_Clear(BLACK);
    while(key != KEY_BACK)
    {
        key = check_key();
        TFT_String(5,5,WHITE,BLACK, (uint8_t *)"uart test.");
        if (modUart.needRefresh){
            TFT_Clear(BLACK);
            modUart.needRefresh = false;
        }
        TFT_String(5,30,WHITE,BLACK,modUart.memPool);
//         UARTSend((uint8_t *)"hahahah", 7);
    }
}

void UARTSend(const uint8_t *pucBuffer, uint32_t ulCount) {
    while(ulCount--) {
        UARTCharPutNonBlocking(UART5_BASE, *pucBuffer++);
    }
}

void UARTtx(uint8_t data) {
    UARTCharPutNonBlocking(UART5_BASE, data);
    modUart.tx_data = data;
}